%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Definici�n del tipo de documento.                                           %
% Posibles tipos de papel: a4paper, letterpaper, legalpapper                  %
% Posibles tama�os de letra: 10pt, 11pt, 12pt                                 %
% Posibles clases de documentos: article, report, book, slides                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass[a4paper,11pt]{article}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Los paquetes permiten ampliar las capacidades de LaTeX.                     %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Paquete para inclusi�n de gr�ficos.
\usepackage[pdftex]{graphicx}

% Paquete para definir la codificaci�n del conjunto de caracteres usado
% (latin1 es ISO 8859-1).
\usepackage[utf8]{inputenc}

% Paquete para definir el idioma usado.
\usepackage[spanish]{babel}
\usepackage{float}
\usepackage{url}
\usepackage{enumerate}
\usepackage{anysize}

% T�tulo principal del documento.
\title{		\textbf{Trabajo pr\'actico 2: \\ Arquitecturas de Memoria \\[3ex]}}

% Informaci�n sobre los autores.
\author	{ 	Badano Juan Ignacio, \textit{Padr\'on Nro. 90.241}                      \\
            \texttt{ j\_badano@hotmail.com }                                            \\
            Liva Mar\'ia Eugenia, \textit{Padr\'on Nro. 86.123}                     	\\
            \texttt{ m.eugenia@liva.net.ar }                                            \\
            Retyk Federico, \textit{Padr\'on Nro. 90.597}                     		\\
            \texttt{ fede.retyk@gmail.com }                                             \\[3ex]
            \normalsize{66.20 Organizaci\'on de Computadoras}                           \\
            \normalsize{Facultad de Ingenier\'ia, Universidad de Buenos Aires}          \\
       }

\date{Jueves 16 de junio de 2011}

\begin{document}

% Inserta el t�tulo.
\maketitle

% Quita el n�mero en la primer p�gina.
\thispagestyle{empty}

% Resumen
\begin{abstract}
En el presente informe se describe el diseño de una <<suite>> de <<benchmarks>> destinado a calcular los parámetros de una Memoria Caché: tasa de desaciertos, tamaño de bloque y cantidad de vías.

Para determinar la arquitectura se utilizó como herramienta principal, el <<profiler>> Cachegrind.
\end{abstract}

\newpage

\tableofcontents

\newpage

\section{Enunciado}

\subsection{Objetivos}

Familiarizarse con la medición de comportamiento utilizando herramientas de profiling y con la estimación de parámetros de una memoria caché a partir de patrones de acceso y tasa de desaciertos al implementar un suite de benchmarking de memorias caché

\subsection{Alcance}

Este trabajo práctico es de elaboración grupal, evaluación individual, y de carácter obligatorio para todos alumnos del curso.

\subsection{Recursos}

Para la realización de este trabajo práctico, se requiere la herramienta de debugging y profiling Valgrind, la cual puede conseguirse en
http://valgrind.org/. Esta herramienta es de fácil instalación, y corre en ambientes Linux x86. En particular, se utilizará el módulo Cachegrind para simulación de memorias caché.\\

En http://valgrind.org/docs/manual/index.html podrán hallar abundante documentación.

\subsection{Software a Evaluar}

\subsubsection{Objetivo}

Determinar el tamaño de bloque, la cantidad de vías y el tamaño total de una memoria caché de datos. Esta puede ser la simulada al utilizar la
herramienta Cachegrind o la propia del procesador donde se ejecute el suite
de benchmarking desarrollado. Este trabajo es de libre realización, pero se aconseja seguir el modelo que se propone en la siguiente sección. Se pueden utilizar los lenguajes C o C++.

\subsubsection{Modelo Propuesto}

\begin{enumerate}[1.]
\item Realizar un módulo (herramienta parser) que parsee los datos del
archivo de salida del módulo Cachegrind para que obtenga la tasa
de miss de la memoria caché de datos.

\item Realizar un módulo que ejecute una implementación del modelo de lazo
simple para obtener el tamaño del bloque de la memoria caché midiendo la tasa de miss 
que proporciona la herramienta parser desarrollada en el paso anterior.

\item Realizar un módulo que ejecute una implementación del modelo de lazo simple 
para obtenter el tamaño total de la memoria caché bajo estudio midiendo la tasa de 
miss que proporciona la herramienta parser desarrollada en el primer paso.

\item Realizar un módulo que ejecute una implementación del modelo de
lazo simple para obtener la cantidad de vías de la memoria caché bajo
estudio midiendo la tasa de miss que proporciona la herramienta parser
desarrollada en el primer paso.

\item Realizar un programa que ejecute los módulos anteriores en el orden
debido, proporcionando los datos que sean necesarios para cada uno y
provea en su salida la información de la memoria caché estudiada.
\end{enumerate}

\subsubsection{Parámetros del Programa Principal}

Se deberán implementar las opciones: \\

\begin{verbatim}
-v, –version
-h, –help
\end{verbatim}

En caso de existir errores, estos deben ser impresos por stderr.

\subsubsection{Salida del Programa Principal}

La salida del programa principal debe ser por stdout y tener el siguiente
formato:\\
\begin{verbatim}
\$>tp2
Memoria Caché de Datos Analizada:
#Vías: X Vías
Tamaño Total: Y Bytes
Tamaño de Bloque: Z Bytes
\end{verbatim}

\subsection{Informe}
El informe deberá incluir:

\begin{itemize}
\item Este enunciado.
\item Descripción de los módulos realizados.
\item Detalle del funcionamiento de cada módulo (Explicando cómo se calculan los distintos parámetros de la memoria caché).
\item Modelo de uso del suite de benchmarking.
\item Pruebas realizadas para la comprobación del correcto funcionamiento de cada módulo.
\end{itemize}

\section{Introducción}

\subsection{Memoria Caché - Principios básicos}

El objetivo de la memoria cache es lograr que la velocidad de
la memoria sea lo mas rapida posible, consiguiendo al mismo
tiempo un tamaño grande al precio de memorias
seminconductoras menos costosas.\\

El caché contiene una copia de partes de la memoria
principal. Cuando el procesador intenta leer una palabra de
memoria, se hace una comprobación para determinar si la
palabra está en el caché. Si es así se entrega dicha palabra al
procesador. Si no, un bloque de memoria principal, consistente
en un cierto número de palabras se transfiere a la caché y
después, la palabra es entregada al procesador.\\

Debido al fenómeno de localidad de las referencias cuando un
bloque de datos es captado por la caché para satisfacer una
referencia a memoria simple, es probable que se hagan
referencias futuras a otras palabras del mismo bloque.

\subsection{Tipos de Memoria Caché}

\begin{itemize}
\item \textbf{De mapeo directo} (<<Direct mapped>>): Cada sector específico de la cache corresponde a
varios sectores específicos de la memoria principal.
Cada vez que el procesador pide un dato, la controladora
de caché debe ir a esa ubicación para encontrar la
información, ahorrando tiempo de búsqueda. \\

La gran desventaja de esta arquitectura de caché es que
al corresponder varios bloques de memoria RAM al
mismo bloque en la caché, si un programa accede a estos
datos, la caché estará constantemente accediendo a la
memoria principal para actualizar la información.

\item \textbf{Totalmente asociativa} (<<Fully associative>>): Los bloques de la memoria principal se trasladan en
cualquier bloque libre de la caché.\\

La ventaja de esta arquitectura es que la información a
la que accedió recientemente se encuentra presente casi
siempre en la caché y también los datos concurrentes.\\

La desventaja es que la búsqueda de datos se debe
hacer en forma indexada y lenta, lo que indica que se
debe recorrer los bloques de la caché en búsqueda del
bloque de memoria deseado.

\item \textbf{Asociativa por vías} (<<N-ways set associative>>):Está dividida en varios conjuntos: dos, cuatros u ocho,
con múltiples sectores y cada uno de ellos conteniendo
un bloque de datos. \\

Cada bloque de memoria principal
puede estar representado en cualquiera de los conjuntos,
pero solamente puede almacenarse una sección de
memoria por conjunto.\\

En un caché asociativa de conjuntos de dos vías, tiene
solamente dos lugares para un bloque especifico de
memoria, reduciéndose el tiempo de búsqueda y la
posibilidad de que los datos utilizados frecuentemente se
sobrescriban entre sí. [1]

\end{itemize}

\section{Benchmarks}

\subsection{Herramientas}

\subsubsection{Cachegrind}
<<Cachegrind>> es un perfilador de memoria caché. Realiza simulaciones detalladas de memorias caché L1, D1 y L2 para determinar la fuente de los desaciertos en el código fuente ejecutado. El código puede estar escrito en cualquier lenguaje de programación. \\

Identifica los lugares donde se producen desaciertos, referencias a memoria e instrucciones ejecutadas para cada línea del código fuente, devolviendo resúmenes por funciones, módulos o programas completos. [2]\\

\subsubsection{Otros}
Los códigos fuentes de los distintos <<benchmarks>> fueron implementados en lenguaje \textbf{C}.\\
 
La interfaz para el seteo de datos de los módulos se implementó en el lenguaje de <<scripting>>  \textbf{Bash}, para facilitar la invocación de los distintos módulos, el pasaje de datos de uno a otro y la impresión final en pantalla con los resultados del proceso.

\subsection{Diseño y modo de uso}

La implementación está organizada de la siguiente manera: \\

Un m\'odulo principal codificado en lenguaje C, llamado \textbf{tp2.c}, que ejecuta el script de Bash \textbf{modulos.sh}. Dicho script se encarga de ejecutar cada uno de los módulos necesarios para obtener los parámetros de la caché.\\

Todos los archivos .c y .sh deben ubicarse en el mismo directorio y compilar el módulo principal con el siguiente comando:\\

\begin{center}
\texttt{gcc -o tp2 tp2.c}
\end{center}

El programa, sin especificar opciones, devuelve por \texttt{stdout} los resultados, con el formato previsto.\\

Las opciones pueden ser:
\begin{itemize}
 \item -h, --help : Imprime la version del programa.
 \item -v, --version : El cual imprime informaci\'on de como usar el programa.
\end{itemize}

Cabe destacar que si se invoca el programa con n\'umeros inv\'alidos, es decir, n\'umeros fuera del rango [2 , MAXINT], \'este retorna un error.

\subsubsection{Parámetros de Caché propia}

Para conocer los parámetros de la caché que utiliza el procesador propio, se debe ejecutar la aplicación sin argumentos:\\

\begin{center}
\texttt{./tp2}
\end{center}

\subsubsection{Parámetros de Caché simulada}


Para obtener los parámetros de una caché simulada se deben ingresar como argumentos: la cantidad de vías (V), tamaño de bloque (B) y tamaño  total de la caché (T). Ej.:\\

\begin{center}
\texttt{./tp2 -V 4 -T 2048 -B 32}
\end{center}

\subsubsection{Parser}
Se trata de un script de Bash, llamado \textbf{parser.sh}, que es utilizado por los dem\'as modulos. Dado un <<benchmark>> el parser devuelve informaci\'on respecto a las escrituras de datos en la cach\'e L1.

\begin{center}
\texttt{./parser.sh benchmark.c CANT}
\end{center}

Se puede solicitar la cantidad de misses para una l\'inea dada (mediante el par\'ametro CANT), o bien la tasa de misses para esa l\'inea. La linea para la cual calcula esos valores es arbitraria y fue dise\~{n}ada por nosotros para obtener los mejores resultados posibles. Ver código fuente en \ref{an1}. Anexo I: Código Fuente.\\

\subsection{Tamaño de Bloque}
El m\'odulo que se encarga de obtener el tamaño de un bloque, llamado tam\_bloque.sh, funciona de la siguiente manera. Se ejecuta un benchmark que denominamos bench1.c, el cual recorre una vez un vector de 1024 bytes (que suponemos, ser\'a el tamaño m\'aximo de bloque).\\

A partir de esa corrida, el parser devuelve la tasa de misses (calculada como cantidad de misses sobre cantidad de accesos a memoria). El tamaño de bloque, por lo tanto, es la inversa de ese valor.

\subsection{Tamaño de la Caché}
Este m\'odulo  se encarga de determinar el tamaño de total de la memoria cach\'e de datos L1. Lo llamamos tam\_cache.sh y trabaja de la siguiente manera. Se ejecuta un benchmark que denominamos bench2.c, al cual le especificamos el tamaño de un bloque y la cantidad de bloques que tiene la cach\'e.\\ 

Comenzando por una cantidad igual a 1 y duplicando esa cantidad en cada iteraci\'on, el m\'odulo prueba recorrer una gran cantidad de veces un mismo lazo de tamaño de un bloque por la cantidad supuesta de bloques en cach\'e, y de tener una cantidad de misses menor o igual al tamaño del lazo, contin\'ua iterando.\\ 

De tener una cantidad de misses mayor, quiere decir que el tamaño de la cach\'e era el tamaño de lazo que se utiliz\'o en la iteraci\'on anterior.\\

Es interesante destacar que en todos los benchmarks, antes de ejecutar las lecturas o escrituras de los lazos, se limpia la cach\'e leyendo otro lazo significativamente grande, para evitar que alg\'un dato ya estuviera previamente cargado en cach\'e y arruine las mediciones.

\subsection{Cantidad de vías}
El \'ultimo m\'odulo se encarga de averiguar la cantidad de v\'ias de la memoria cach\'e de datos, conociendo de antemano el tamaño de bloque y de la memoria cach\'e.\\ 

Para ello se recorre una matriz cuya cantidad de filas es igual a la cantidad de v\'ias que suponemos que tiene m\'as una (esta \'ultima, si supusimos bien la cantidad de v\'ias, solapar\'a el bloque menos recientemente usado de ese conjunto), y de una cantidad de columnas igual al tamaño de la memoria cach\'e.\\

Despu\'es de recorrer cada una de las columnas de la matriz, de forma de haber cargado todas al menos en algun momento en memoria, lee nuevamente la primer posicion de cada fila.\\

Entonces bien, si todas las filas pudieron coexistir en memoria, es por que supusimos mal la cantidad de v\'ias, el numero que supusimos era demaciado chico. De esta forma, comenzamos iterando con una cantidad de v\'ias supuesta igual a uno, y duplicamos si nos habiamos equivocado.\\

Para mayor claridad, puede analizarse el c\'odigo presentado.

\section{Ejecución de Pruebas}

\begin{figure}[H]
\center{\includegraphics[width=17cm]{tp2-1.png}}
\caption{Obtención de los parámetros de la Memoria Caché propia} \label{fig001}
\end{figure}

\begin{figure}[H]
\center{\includegraphics[width=17cm]{tp2-2.png}}
\caption{Obtención de los parámetros de la Memoria Caché simulada} \label{fig002}
\end{figure}

\newpage
\section{Conclusiones}

\newpage
\section{Anexo I: Código Fuente}\label{an1}

\subsection{Benchmarks}

\large{\textbf{Tamaño de Bloque (bench1.c)}}

\begin{verbatim}
#define TAM 1024

int main()
{
	register int i, j;

	char clr[4194304];
	char a[TAM];

	for( i=0 ; i<4194304 ; i++ )
	{
		clr[i]='p';
	}

	for( i=0 ; i<TAM ; i++ )
	{
		a[i]='k';
	}

	return 0;
}
\end{verbatim}

\large{\textbf{Tamaño Total (bench2.c)}}

\begin{verbatim}
#define B XX 				//TAMAÑO DE BLOQUE
#define TAM YY 				//TAMAÑO DEL LAZO
#define INFINITO 32768 		//TAMAÑO MUY GRANDE


int main()
{
	register int i;
	register int j;
	char clr[INFINITO];
	char a[TAM];

	for( i=0 ; i<INFINITO ; i++ )
	{
		clr[i]='p';
	}

	for( j=0 ; j<2 ; j++ ){
		for( i=0 ; i<TAM ; i+=B )
		{
			a[i]='k';
		}
	}

	return 0;
}
\end{verbatim}

\large{\textbf{Cantidad de vías (bench3.c)}}

\begin{verbatim}
#define B XX
#define TAM YY
#define VIAS ZZ
#define INFINITO 32768

int main()
{
	register int i, j, tam, vias, largo;

	tam = TAM;
	vias = VIAS;

	// Para una dada cantidad de vías, genera una cantidad de lazos 
	igual a la cantidad de vías mas uno.
	vias *= 2;
	largo = tam / vias;

	char clr[INFINITO];
	char a[vias][TAM];

	for( i=0 ; i<INFINITO ; i++ )
	{
		clr[i]='p';
	}

	for( i=0 ; i<vias ; i++ )
	{
		for( j=0 ; j<largo ; j+=B )
		{
			a[i][j]='m';
		}
	}

	for( i=0 ; i<vias ; i++ )
	{
		a[i][0]='k';
	}

	return 0;
}
\end{verbatim}

\subsection{Scripts}

\large{\textbf{parser.sh}}

\begin{verbatim}
#!/bin/bash

# Precondiciones:
# 1. el código fuente pasado por parámetro debe existir y tener formato 
válido para el parseo.

# Compila adecuadamente el código dado como argumento.
gcc -o prueba -g3 -std=c99 -O0 $1

# Ejecuta la corrida de valgrind sobre.
if [ $# -gt 4 ]
then
	valgrind -q --tool=cachegrind --cachegrind-out-file=salida 
	--D1=$3,$4,$5 ./prueba
else
	valgrind -q --tool=cachegrind --cachegrind-out-file=salida ./prueba
fi


# Corre cg_annotate sobre el archivo de salida.
cg_annotate --auto=yes --show=Dw,D1mw salida $1 > aparsear.txt
if [ $2 = "VIAS" ]
then
	
	# Parsea el resultado.
	variable=`grep -F "a[i][0]='k'" aparsear.txt | 
	sed 's/ *\([^ ]*\) *\([^ ]*\)/\1 \2 /g'`
  writes=`echo $variable | cut -f1 -d' ' | sed 's/,//g'`
  misses=`echo $variable | cut -f2 -d' ' | sed 's/,//g'`

	if [ $writes = '.' ]
	then
		writes=1
	fi
	if [ $misses = '.' ]
	then
		misses=0
	fi
	resultado=`echo "scale=4;$misses/$writes" | bc`
	echo $resultado
else
	# Parsea el resultado.
	variable=`grep -F "a[i]='k'" aparsear.txt | 
	sed 's/ *\([^ ]*\) *\([^ ]*\)/\1 \2 /g'`
	writes=`echo $variable | cut -f1 -d' ' | sed 's/,//g'`
	misses=`echo $variable | cut -f2 -d' ' | sed 's/,//g'`
	
	# Imprime el resultado
	if [ $2 = "CANT" ]
	then
		echo "$misses"
	else
		resultado=`echo "scale=4;$misses/$writes" | bc`
		echo "$resultado"
	fi
fi

# Elimina archivos temporales.
rm aparsear.txt
rm salida
rm prueba

exit 0
\end{verbatim}

\large{\textbf{modulos.sh}}

\begin{verbatim}
#!/bin/bash

# Setea permisos de ejecucion.
chmod 755 parser.sh
chmod 755 tam_bloque.sh
chmod 755 tam_cache.sh
chmod 755 cant_vias.sh

# Calcula el tamaño de bloque.
if [ $# -gt 2 ]
then
	bloque=`./tam_bloque.sh $1 $2 $3`
else
	bloque=`./tam_bloque.sh`
fi

# Con esa informacion calcula el tamaño total de la cache.
if [ $# -gt 2 ]
then
	tamanio=`./tam_cache.sh $bloque $1 $2 $3`
else
	tamanio=`./tam_cache.sh $bloque`
fi


# A partir de esos datos, calcula la cantidad de vías.
if [ $# -gt 2 ]
then
	vias=`./cant_vias.sh $bloque $tamanio $1 $2 $3`
else
	vias=`./cant_vias.sh $bloque $tamanio`
fi


# Por último, imprime los resultados
echo "Memoria caché de datos Analizada:"
echo "#Vias: $vias"
echo "Tamaño Total: $tamanio Bytes"
echo "Tamaño de Bloque: $bloque Bytes"

exit 0
\end{verbatim}

\large{\textbf{tam\_bloque.sh}}
\begin{verbatim}
#!/bin/bash

i=1
res=0

#
# Calcula la tasa de misses (Dw / D1mw) para escrituras en 
la memoria caché L1 de datos.
#
if [ $# -gt 1 ]
then
	missrate=`./parser.sh bench1.c RATE $1 $2 $3`
else
	missrate=`./parser.sh bench1.c RATE`
fi
resultado=`echo "$missrate ^ -1" | bc`

echo $resultado

exit 0
\end{verbatim}

\large{\textbf{tam\_cache.sh}}
\begin{verbatim}
#!/bin/bash

i=1
ejecucion=0

bloque=$1

sed "s/XX/$bloque/" bench2.c > bench_tm.c

#
# Comienza a probar distintos tamaños.
#
until [[ $ejecucion -gt $i ]]
do
	i=`echo "$i*2" | bc`
	tam=`echo "$bloque * $i" | bc`
	sed "s/YY/$tam/" bench_tm.c > bench_tam.c
	if [ $# -gt 2 ]
	then
		ejecucion=`./parser.sh bench_tam.c CANT $2 $3 $4`
	else
		ejecucion=`./parser.sh bench_tam.c CANT`
	fi
	rm bench_tam.c
done

#
# Devuelve el resultado.
#
tam=`echo "$tam / 2" | bc`
echo $tam

#
# Elimina archivo auxiliar.
#
rm bench_tm.c

exit 0
\end{verbatim}


\large{\textbf{cant\_vias.sh}}
\begin{verbatim}
#!/bin/bash

# Precondiciones:
# 1. debe conocerse el tamaño de bloque y debe pasarse como argumento 
$1.
# 2. debe conocerse el tamaño total de caché y debe pasarse como 
argumento $2.



bloq=$1
tam=$2
i=1
rate=0

# Setea el tamaño del bloque en el benchmark.
sed "s/XX/$bloq/" bench3.c > bench_bloque.c

# Setea el tamaño total de la caché en el benchmark.
sed "s/YY/$tam/" bench_bloque.c > bench_tam.c

until [[ $rate -ge 1 ]]
do
	i=`echo "$i * 2" | bc`
	sed "s/ZZ/$i/" bench_tam.c > bench_vias.c
	if [ $# -gt 4 ]
	then
		ejec=`./parser.sh bench_vias.c VIAS $3 $4 $5`
	else
		ejec=`./parser.sh bench_vias.c VIAS`
	fi
	rate=${ejec%%.*}
	rm bench_vias.c	
done

rm bench_tam.c
rm bench_bloque.c

echo $i

exit 0
\end{verbatim}

\subsection{Módulo principal}

\large{\textbf{tp2.c}}

\begin{verbatim}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

void tp2_reverse(char s[])
 {
     int i, j;
     char c;
 
     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
 }


void tp2_itoa(int n, char s[])
 {
     int i, sign;
 
     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     tp2_reverse(s);
 }


void imprime_version () {
  printf ("tp2 - version: 1.0\n");
}

void imprime_uso () {
  printf ("tp2   Usage:\n\n"
	  "   tp2 [options]\n"
	  "   tp2 - Programa que analiza la caché de datos de la máquina 
	  donde se ejecuta.\n\n"
	  "   Options:\n"
	  "   		-v, --version      Imprime la versión.\n"
	  "   		-h, --help         Imprime esta ayuda.\n"
	  "   		-T, --tam         Setea el tamaño total de la cache a 
	  simular (funciona si sólo si también se usan -V y -B).\n"
	  "   		-V, --vias         Setea la cantidad de vías de la 
	  cache a simular (funciona si sólo si también se usan -T y -B).\n"
	  "   		-B, --bloque         Setea el tamaño de bloque de 
	  la cache a simular (funciona si sólo si también se usan -T y -V)
	  .\n");
}

int main (int argc, char *argv[]) {
  int c;
  int tam = 0, vias = 0, bloque = 0;
  int b_tam = 0, b_vias = 0, b_bloque = 0;

  char salida[50];
  char s_tam[10];
  char s_via[10];
  char s_blq[10];

  while (1) {
    static struct option long_options[] = {
      {"version", no_argument, 0, 'v'},
      {"help", no_argument, 0, 'h'},
      {"tam", required_argument, 0, 'T'},
      {"vias", required_argument, 0, 'V'},
      {"bloque", required_argument, 0, 'B'},
      {0, 0, 0, 0}
    };
    int option_index = 0;
    c = getopt_long (argc, argv, "vhT:V:B:", long_options, &option_
    index);

    if (c == -1)
      break;

    switch (c) {
    case 'v':
      imprime_version ();
      return 0;
      break;

    case 'h':
      imprime_uso ();
      return 0;
      break;

    case 'T':
      tam = atoi (optarg);
      b_tam = 1;
      break;

    case 'V':
      vias = atoi (optarg);
      b_vias = 1;
      break;

    case 'B':
      bloque = atoi (optarg);
      b_bloque = 1;
      break;

    case '?':
      fprintf (stderr, "Error en los parámetros\n");
      return -1;
      break;

    default:
      abort ();
    }
  }

  /* Se ejecuta el script que maneja los distintos módulos.*/
	
  system("chmod 755 modulos.sh");

  if( (b_bloque==1) && (b_vias==1) && (b_tam==1) )
  {     
      strcpy(salida,"./modulos.sh ");

      tp2_itoa(tam,s_tam);
      strcat(salida,s_tam);
      strcat(salida," ");
      tp2_itoa(vias,s_via);
      strcat(salida,s_via);
      strcat(salida," ");
      tp2_itoa(bloque,s_blq);
      strcat(salida,s_blq);
      strcat(salida," ");
    
      system(salida);
  }
  else
  {
    system("./modulos.sh");
  }

  return 0;
}
\end{verbatim}

% Citas bibliogr�ficas.
\begin{thebibliography}{99}
\bibitem{[1]} Memoria Caché, Webcindario, \url{http://carteleras.webcindario.com/}
\bibitem{[2]} Cachegrind, Valgrind Tool Suite, \url{http://valgrind.org/info/tools.html#cachegrind}
\end{thebibliography}

\end{document}
